package com.geiliwang.web.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.geiliwang.web.config.RedisClient;
import com.geiliwang.web.config.SmsConfig;
import com.geiliwang.web.entity.SmsInfo;
import com.geiliwang.web.service.SmsService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Configuration
@EnableConfigurationProperties(SmsConfig.class)
public class AliSmsServiceImpl implements SmsService {

    private static final Logger logger = LoggerFactory.getLogger(AliSmsServiceImpl.class);
    static SmsConfig smsConfig;

    @Bean
    public SmsConfig getSmsConfig(SmsConfig smsConfig) {
        AliSmsServiceImpl.smsConfig = smsConfig;
        return smsConfig;
    }

    private static void setSmsConfig(SmsConfig smsConfig) {
        AliSmsServiceImpl.smsConfig = smsConfig;
    }

    //产品名称:云通信短信API产品,开发者无需替换
    private static final String product = "Dysmsapi";
    //产品域名,开发者无需替换
    private static final String domain = "dysmsapi.aliyuncs.com";

    // TODO 此处需要替换成开发者自己的AK(在阿里云访问控制台寻找)
//    static final String accessKeyId = "LTAIj9YD3l0huVLO";
//    static final String accessKeySecret = "DzWylduSjJ8ghTFNOv8iklaKRV2eKV";

    private static String sendSms(SmsInfo smsInfo) throws ClientException, InterruptedException {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", smsConfig.getAccessId(), smsConfig.getAccessKey());
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        //组装请求对象-具体描述见控制台-文档部分内容
        SendSmsRequest request = new SendSmsRequest();
        //必填:待发送手机号
        request.setPhoneNumbers(smsInfo.getPhone());
        //必填:短信签名-可在短信控制台中找到

        if(StringUtils.isBlank(smsInfo.getSignName())) {
            request.setSignName(smsConfig.getSignName());
        } else {
            request.setSignName(smsInfo.getSignName());
        }

        //必填:短信模板-可在短信控制台中找到
        request.setTemplateCode(smsInfo.getSMSTempateCode());
        //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
//        request.setTemplateParam("{\"customer\":\"test\"}");
        request.setTemplateParam(JSONObject.toJSON(smsInfo.getSMSTemplateParams()).toString());
        //选填-上行短信扩展码(无特殊需求用户请忽略此字段)
        //request.setSmsUpExtendCode("90997");
        //可选:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        request.setOutId("yourOutId");
        //hint 此处可能会抛出异常，注意catch
        SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
        sendSmsLog(sendSmsResponse);
        return sendSmsResponse.getBizId();
    }

    @Override
    public String sendSms(String phone, String signName, String SMSTempateCode, Map<String, String> params) throws Exception {
        SmsInfo info = new SmsInfo();
        info.setPhone(phone);
        info.setSignName(signName);
        info.setSMSTempateCode(SMSTempateCode);
        info.getSMSTemplateParams().putAll(params);
        return sendSms(info);
    }

    @Override
    public String sendSmsVcode(String phone, String signName, String SMSTempateCode, Map<String, String> params) throws Exception {
        SmsInfo info = new SmsInfo();
        info.setPhone(phone);
        info.setSignName(signName);
        info.setSMSTempateCode(SMSTempateCode);
        String vCode = AliSmsServiceImpl.createRandomVcode();
        params.put("code", vCode);
        info.getSMSTemplateParams().putAll(params);
        String messageId = sendSms(info);
        setVerificationCode(messageId, vCode, phone);
        return messageId;
    }

    @Override
    public boolean checkSmsVcode(String messageId, String userVcode) throws ParseException {
        return checkSmsVcode(messageId, userVcode, null);
    }

    @Override
    public boolean checkSmsVcode(String messageId, String userVcode, String phone) throws ParseException {
        boolean success = false;
        HashMap<String, String> resultList = getVerificationCode(messageId);
        if (resultList != null) {
            String SysVcode = resultList.get("vCode");
            String time = resultList.get("time");
            Date date = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.UK).parse(time);
            date.setTime(date.getTime() + 2 * 60 * 1000);
            //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //校验手机号是否正确
            if (null != phone) {
                if (!phone.equals(resultList.get("phone"))) {
                    return success;
                }
            }

            if (userVcode != null && userVcode.equals(SysVcode) && date.getTime() >= new Date().getTime()) {
                success = true;
            }
        }
        return success;
    }

    @Override
    public void recordErrorMsg(String msgId, String receiver, String errorCode) {

    }

    @Override
    public String batchSendSms(List<String> phones, String signName, String SMSTempateCode, Map<String, String> params) throws Exception {
        String sendPhones = "";
        for (String phone : phones
                ) {
            sendPhones += phone + ",";
        }
        SmsInfo info = new SmsInfo();
        info.setPhone(sendPhones);
        info.setSignName(signName);
        info.setSMSTempateCode(SMSTempateCode);
        info.getSMSTemplateParams().putAll(params);
        String messId = sendSms(info);
        recordMsgInfo(buildSendKey(messId), info);
        return messId;
    }

    //存验证码
    private static void setVerificationCode(String MessageId, String vCode, String phone) throws Exception {
        HashMap<String, String> map = new HashMap<>();
        map.put("vCode", vCode);
        map.put("phone", phone);
        map.put("time", new Date().toString());
        RedisClient.setHashMap(MessageId, map, 300);
    }

    //取验证码
    private static HashMap<String, String> getVerificationCode(String messageId) {
        try {
            HashMap<String, String> map = RedisClient.getHashMap(messageId);
//            List<String> list = new ArrayList<>();
//            for (String key : map.keySet()
//                    ) {
//                list.add(map.get(key));
//                logger.info(map.get(key));
//            }
            return map;
        } catch (NullPointerException e) {
            logger.info("验证码为空，或已过期!");
            return null;
        }

    }

    //短信验证码生成
    private static String createRandomVcode() {
        String vcode = "";
        for (int i = 0; i < 6; i++) {
            vcode = vcode + (int) (Math.random() * 9);
        }
        return vcode;
    }

    /**
     * 记录发送的短信
     *
     * @param msgId
     * @param smsInfo
     */
    static void recordMsgInfo(String msgId, SmsInfo smsInfo) {
        HashMap<String, String> map = new HashMap<>();
        map.put("signName", smsInfo.getSignName());
        map.put("phone", smsInfo.getPhone());
        map.put("SMSTempateCode", smsInfo.getSMSTempateCode());
        map.put("msgId", msgId);
        String paramStr = JSON.toJSONString(smsInfo.getSMSTemplateParams());
        map.put("paramStr", paramStr);

        RedisClient.setHashMap(buildSendKey(msgId), map, 180);
    }

    /**
     * 获取短信消息记录
     *
     * @param msgId
     * @return
     */
    static SmsInfo getRecordMsg(String msgId) {
        SmsInfo result = null;
        try {
            HashMap<String, String> map = RedisClient.getHashMap(buildSendKey(msgId));
            result = new SmsInfo();
            result.setSignName(map.get("signName"));
            result.setPhone(map.get("phone"));
            result.setSMSTempateCode(map.get("SMSTempateCode"));
            @SuppressWarnings("unchecked")
            Map<String, String> SMSTemplateParams = JSON.parseObject(map.get("paramStr"), HashMap.class);
            result.setSMSTemplateParams(SMSTemplateParams);

        } catch (Exception e) {
            logger.info("获取短信记录失败 msgId = " + msgId);
        }

        return result;
    }


    /**
     * 构建消息发送key
     *
     * @param msgId
     * @return
     */
    private static String buildSendKey(String msgId) {
        return "send_" + msgId;
    }

    /**
     * 查询短信发送状态
     *
     * @param bizId（msgId）
     * @return
     */
    public static QuerySendDetailsResponse querySendDetails(String bizId) throws ClientException {
        //可自助调整超时时间
        System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
        System.setProperty("sun.net.client.defaultReadTimeout", "10000");
        //初始化acsClient,暂不支持region化
        IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", smsConfig.getAccessId(), smsConfig.getAccessKey());
        DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", product, domain);
        IAcsClient acsClient = new DefaultAcsClient(profile);
        //组装请求对象
        QuerySendDetailsRequest request = new QuerySendDetailsRequest();
        //必填-号码
        request.setPhoneNumber("15000000000");
        //可选-流水号
        request.setBizId(bizId);
        //必填-发送日期 支持30天内记录查询，格式yyyyMMdd
        SimpleDateFormat ft = new SimpleDateFormat("yyyyMMdd");
        request.setSendDate(ft.format(new Date()));
        //必填-页大小
        request.setPageSize(10L);
        //必填-当前页码从1开始计数
        request.setCurrentPage(1L);
        //hint 此处可能会抛出异常，注意catch
        QuerySendDetailsResponse querySendDetailsResponse = acsClient.getAcsResponse(request);
        return querySendDetailsResponse;
    }

    private static void sendSmsLog(SendSmsResponse response) throws ClientException, InterruptedException {
        logger.info("短信接口返回的数据----------------");
        logger.info("Code=" + response.getCode());
        logger.info("Message=" + response.getMessage());
        logger.info("RequestId=" + response.getRequestId());
        logger.info("BizId=" + response.getBizId());
        //Thread.sleep(3000L);
        //查明细
        if (response.getCode() != null && response.getCode().equals("OK")) {
            QuerySendDetailsResponse querySendDetailsResponse = querySendDetails(response.getBizId());
            logger.info("短信明细查询接口返回数据----------------");
            logger.info("Code=" + querySendDetailsResponse.getCode());
            logger.info("Message=" + querySendDetailsResponse.getMessage());
            int i = 0;
            for (QuerySendDetailsResponse.SmsSendDetailDTO smsSendDetailDTO : querySendDetailsResponse.getSmsSendDetailDTOs()) {
                logger.info("SmsSendDetailDTO[" + i + "]:");
                logger.info("Content=" + smsSendDetailDTO.getContent());
                logger.info("ErrCode=" + smsSendDetailDTO.getErrCode());
                logger.info("OutId=" + smsSendDetailDTO.getOutId());
                logger.info("PhoneNum=" + smsSendDetailDTO.getPhoneNum());
                logger.info("ReceiveDate=" + smsSendDetailDTO.getReceiveDate());
                logger.info("SendDate=" + smsSendDetailDTO.getSendDate());
                logger.info("SendStatus=" + smsSendDetailDTO.getSendStatus());
                logger.info("Template=" + smsSendDetailDTO.getTemplateCode());
            }
            logger.info("TotalCount=" + querySendDetailsResponse.getTotalCount());
            logger.info("RequestId=" + querySendDetailsResponse.getRequestId());
        }

    }
}
